home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 10 - 1994 / 10.11 Nov 94 / DragNDropForSmalltalk next >
Encoding:
Text File  |  1994-10-12  |  8.7 KB  |  351 lines  |  [TEXT/R*ch]

  1. This is the source text from David Simmons' "Implementing Elegant Drag and Drop
  2. for Styled Text Fields" article.  It's a bit choppy, but may save some typing for
  3. folks who want to try out parts of it.
  4.  
  5. TEField[i]dragEnter
  6.  
  7.    “Validate whether the package is interesting”
  8.     (Mouse dragPackageDetect: 
  9.         [:type | (type isKindOf: String class)]) 
  10.             ifFalse: [^self].
  11.  
  12. ---
  13.  
  14.    “Compute the drag area and then display it”
  15.     outer := self contentBounds asRegion copy insetBy: (-1 @ -1).
  16.     inner := outer copy insetBy: 2.
  17.     outer differenceWith: inner.
  18.  
  19. ---
  20.  
  21.    Mouse showDragHiliteRegion: outer.
  22.     
  23. ---
  24.  
  25.    “Indicate that we are tracking the drag operation, but that 
  26.     it needs initialization.”
  27.     Mouse dragTargetData: false.
  28.  
  29. ---
  30.  
  31. TEField[i]dragExit
  32.     (data := Mouse dragTargetData) ifTrue:
  33.     [
  34.        “Hide any visible blinking bar we may have showing”
  35.         (data at: 6) value: false.
  36.     ].
  37.     
  38. ---
  39.  
  40.     ^super dragExit
  41.  
  42. ---
  43.  
  44.     #dragEnter
  45.     #dragWithin   “1 or more times depending on whether the 
  46.                    Mouse moves inside of the field”
  47.     #dragExit
  48.  
  49. ---
  50.  
  51. TEField[i]dragWithin
  52.  
  53.     | bottom offset point line localPosition height top data |
  54.  
  55. ---
  56.  
  57.     data := (Mouse dragTargetData) ? [^self].
  58.  
  59. ---
  60.     
  61.    “Compute the offset into the text field”
  62.     offset := self offsetOfPoint: 
  63.         (localPosition := Mouse localPosition).
  64.     
  65. ---
  66.  
  67.     data ifFalse:
  68.     [
  69.  
  70.         line := self lineAtOffset: offset.
  71.         point := self pointAtOffset: offset.
  72.         height := self heightFromLine: line to: line.        
  73.         bottom := point - (1@0).
  74.         top := (bottom - (0@height)).
  75.  
  76.         data :=
  77.         {
  78.             false.              "Not Visible"
  79.             offset.             "old offset"
  80.             top.                "top"
  81.             bottom.             "bottom"
  82.             self hiliteRegion.  "The hilited text region"
  83.             [:doShow |
  84.                 ((data at: 1) = doShow) ifFalse:
  85.                 [
  86.                    “Draw in XOR mode”
  87.                     activeCanvas
  88.                         pushPen;
  89.                         penMode: #patXor;
  90.                         movePenTo: (data@3);
  91.                         drawLineTo: (data@4);
  92.                         popPen.
  93.                         
  94.                    “Update to reflect current state”
  95.                     data at: 1 put: doShow.
  96.                 ].
  97.             ].
  98.         }.
  99.   
  100.       
  101.         Mouse dragTargetData: data.
  102.  
  103.  
  104.     ].
  105.   
  106.   
  107.    “If the mouse is inside the hilited selection, then hide 
  108.     the caret”
  109.     ((Mouse dragInitiator == self)
  110.         and: [(data at: 5) containsPoint: localPosition]) ifTrue:
  111.     [
  112.        ^(data at: 6) value: false
  113.     ].
  114.     
  115.  
  116.    “If it hasn't changed then just toggle/blink the vertical bar”
  117.     (offset = (data at: 2)) ifTrue:
  118.     [
  119.        “Re-draw, toggling the visibility”
  120.         (data at: 6) value: 
  121.             ((Clock ticks // Gestalt DoubleTime) isEven).
  122.     ] 
  123.     
  124.    “Otherwise, erase the old position and recalculate”
  125.     ifFalse:
  126.     [
  127.        “Erase the old position”
  128.         (data at: 6) value: false.
  129.         
  130.         line := self lineAtOffset: offset.
  131.         point := self pointAtOffset: offset.
  132.         height := self heightFromLine: line to: line.        
  133.         bottom := point - (1@0).
  134.         top := (bottom - (0@height)).
  135.         
  136.         data
  137.             at: 2 put: offset;
  138.             at: 3 put: top;
  139.             at: 4 put: bottom.
  140.             
  141.        “Re-draw, toggling the visibility”
  142.         (data at: 6) value: true.
  143.     ].
  144.  
  145.  
  146. TEField[i]dragItemDropped
  147.  
  148.     | selEnd offset dropPoint dragData selStart result |
  149.  
  150.  
  151.    “Grab the target data, if any”
  152.     (dragData := Mouse dragTargetData) ? [^self dragExit].
  153.  
  154.     dropPoint := Mouse localPosition.
  155.     offset := dragData at: 2.
  156.     
  157.     self dragExit.
  158.     
  159.    “If we were the drag initiator, and the drop was inside our
  160.     hilited text, then do nothing.”
  161.     (Mouse dragInitiator == self
  162.         and: [((Mouse dragInitiatorData@1) & 0x44) not
  163.             and: [Keyboard AltKey not]]) ifTrue:
  164.     [
  165.  
  166.  
  167.         ((dragData@5) containsPoint: dropPoint) ifTrue:
  168.         [
  169.             ^self
  170.         ].
  171.         
  172.         selEnd := self selectionEnd.
  173.         selStart := self selectionStart.
  174.   
  175.         (selEnd ≥ selStart) ifTrue:
  176.         [
  177.             | line height point |
  178.  
  179.             
  180.             line := self lineAtOffset: offset.
  181.             height := self heightFromLine: line to: line.        
  182.             point := self pointAtOffset: offset.
  183.             
  184.            “If on the same line then remove the width from
  185.             the offset because it will be cut anyway.”
  186.             ((offset ≥ selStart) 
  187.                 and: [(self lineAtOffset: selStart) = line])
  188.                     ifTrue:
  189.             [
  190.                 point := point - (((dragData@5) bounds 
  191.                              width + 1)@height).
  192.             ] ifFalse:
  193.             [
  194.                 point := point - (1@height).
  195.             ].
  196.  
  197.            “Animate the move operation”
  198.             (dragData@5)
  199.                 zoomBy: (point - ((dragData@5) bounds origin))
  200.                 mode: 1
  201.                 steps: 12
  202.                 rate: 12.
  203.                 
  204.            “Clear the existing selection”
  205.             self doClear.
  206.             
  207.            “Adjust for the portion we remove”
  208.             (selEnd ≤ offset) ifTrue:
  209.             [
  210.                 offset := offset - (selEnd - selStart).
  211.             ].
  212.         ].
  213.         
  214.        “Select the insertion point”
  215.         self selectFrom: offset+1 to: offset. 
  216.        
  217.     ] ifFalse:
  218.     [
  219.        “Revise the insertion point”
  220.         self selectFrom: offset+1 to: offset.
  221.     ].
  222.     
  223.    “Insert the data”
  224.     Mouse dragItemsDo:
  225.     [:index :typeList | mapType |
  226.     
  227.  
  228.         mapType := nil.
  229.         (typeList includes: Text) ifTrue: 
  230.         [
  231.             mapType := Text
  232.         ]
  233.         ifFalse:
  234.         ifFalse:
  235.         [
  236.             (typeList includes: String) ifTrue: 
  237.                 [mapType := String].
  238.         ].
  239.   
  240.       
  241.         mapType ifTrue:
  242.         [
  243.             result ifNil:
  244.             [
  245.                 result := Mouse 
  246.                     extractDragItem: index 
  247.                     asInstanceOf: mapType.
  248.             ] ifNotNil:
  249.             [
  250.                 result := result,(Mouse 
  251.                     extractDragItem: index 
  252.                     asInstanceOf: mapType).
  253.             ].
  254.         ].
  255.  
  256.  
  257.     ].
  258.     
  259.     result ? [^self].
  260.   
  261.   
  262.     self 
  263.         nextPutAll: result;
  264.         selectFrom: offset to: offset+ result size.
  265.     
  266.  
  267. TEField[i]buttonPress: event
  268. ... Portions Deleted ...
  269.  
  270.     (Switch new)
  271.         case: 1 do: 
  272.         [
  273.             (self handleDragEvent: event) ifFalse:
  274.             [
  275.                 <<TEClick(localWhere:long; 
  276.                     (event ShiftKeyOnly):Boolean; self:Handle)>>.
  277.             ].            
  278.         ];
  279.  
  280.     ... Portions Deleted ...
  281.  
  282.         on: event clickCount.
  283.     
  284.     self 
  285.         updateScrollers;
  286.        "scrollSelectionIntoView;"
  287.         privateSetCursor.
  288.         
  289.     canvas popPen. 
  290.     thread popCanvas.
  291.  
  292.  
  293. TEField[i]handleDragEvent: event
  294.  
  295.    “Implement the drag drop defaults”
  296.     ((self->selStart) ≠ (self->selEnd)) ifTrue:
  297.     [   
  298.         | dragRegion |
  299.     
  300.         ((dragRegion := self hiliteRegion) 
  301.             containsPoint: (event localWhere)) ifTrue:
  302.         [
  303.  
  304.             [(Mouse isButton1Down) and: 
  305.                 [(Mouse localWhere maxDelta: event localWhere) 
  306.                     ≤ 2]] whileTrue.
  307.  
  308.             Mouse isButton1Down ifTrue:
  309.             [
  310.                 Mouse 
  311.                     drag: {self selectedContents}
  312.                     withImage: (dragRegion copy differenceWith:
  313.                         (dragRegion copy insetBy: 1))
  314.                     startingFrom: event localWhere
  315.                     initiator: self
  316.                     initiatorData: 
  317.                         {Keyboard metakeys. dragRegion}
  318.  
  319.                    “Don't block initial hilite and don't 
  320.                     auto-center”
  321.                     flags: 0x03.   
  322.                ^true  
  323.  
  324.             ].
  325.         ].
  326.     ].
  327.    ^false
  328.  
  329.  
  330. Mouse Drag Flag Definitions
  331.  
  332.         0x0001 .. Do not initially hilite the drag-source
  333.                   component
  334.         0x0002 .. Do not auto-center the drag-image
  335.         0x0010 .. Restrict dragging to the source Environment
  336.         0x0020 .. Restrict dragging to the source Module
  337.         0x0040 .. Restrict dragging to the source Window”
  338.  
  339. The author can be reached at “David_Simmons@qks.com”. The electronic mail address
  340. “info@qks.com” is available for any product questions you might have. For more
  341. general information on SmalltalkAgents you can access:
  342.  
  343. WorldWideWeb:    
  344.     The QKS World Wide Web site “http://www.qks.com/”.
  345. INTERNET:    
  346.     Anonymous ftp via “ftp.qks.com”.
  347. Compuserve:    
  348.     “Go Smalltalk” 
  349.     or “Go MacDev [Dynamic Languages Section]” 
  350.     or “Go MacDev [Object Oriented Section]”.
  351.